home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / fs / minix / truncate.c < prev   
Encoding:
C/C++ Source or Header  |  1994-06-05  |  4.0 KB  |  190 lines

  1. /*
  2.  *  linux/fs/truncate.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *
  6.  * This file is subject to the terms and conditions of the GNU General Public
  7.  * License.  See the file README.legal in the main directory of this archive
  8.  * for more details.
  9.  */
  10.  
  11. #include <linux/errno.h>
  12. #include <linux/sched.h>
  13. #include <linux/minix_fs.h>
  14. #include <linux/tty.h>
  15. #include <linux/stat.h>
  16. #include <linux/fcntl.h>
  17.  
  18. /*
  19.  * Truncate has the most races in the whole filesystem: coding it is
  20.  * a pain in the a**. Especially as I don't do any locking...
  21.  *
  22.  * The code may look a bit weird, but that's just because I've tried to
  23.  * handle things like file-size changes in a somewhat graceful manner.
  24.  * Anyway, truncating a file at the same time somebody else writes to it
  25.  * is likely to result in pretty weird behaviour...
  26.  *
  27.  * The new code handles normal truncates (size = 0) as well as the more
  28.  * general case (size = XXX). I hope.
  29.  */
  30.  
  31. static int trunc_direct(struct inode * inode)
  32. {
  33.     unsigned short * p;
  34.     struct buffer_head * bh;
  35.     int i, tmp;
  36.     int retry = 0;
  37. #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
  38.  
  39. repeat:
  40.     for (i = DIRECT_BLOCK ; i < 7 ; i++) {
  41.         p = i + inode->u.minix_i.i_data;
  42.         if (!(tmp = *p))
  43.             continue;
  44.         bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  45.         if (i < DIRECT_BLOCK) {
  46.             brelse(bh);
  47.             goto repeat;
  48.         }
  49.         if ((bh && bh->b_count != 1) || tmp != *p) {
  50.             retry = 1;
  51.             brelse(bh);
  52.             continue;
  53.         }
  54.         *p = 0;
  55.         inode->i_dirt = 1;
  56.         brelse(bh);
  57.         minix_free_block(inode->i_sb,tmp);
  58.     }
  59.     return retry;
  60. }
  61.  
  62. static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
  63. {
  64.     struct buffer_head * bh;
  65.     int i, tmp;
  66.     struct buffer_head * ind_bh;
  67.     unsigned short * ind;
  68.     int retry = 0;
  69. #define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
  70.  
  71.     tmp = *p;
  72.     if (!tmp)
  73.         return 0;
  74.     ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  75.     if (tmp != *p) {
  76.         brelse(ind_bh);
  77.         return 1;
  78.     }
  79.     if (!ind_bh) {
  80.         *p = 0;
  81.         return 0;
  82.     }
  83. repeat:
  84.     for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
  85.         if (i < 0)
  86.             i = 0;
  87.         if (i < INDIRECT_BLOCK)
  88.             goto repeat;
  89.         ind = i+(unsigned short *) ind_bh->b_data;
  90.         tmp = *ind;
  91.         if (!tmp)
  92.             continue;
  93.         bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
  94.         if (i < INDIRECT_BLOCK) {
  95.             brelse(bh);
  96.             goto repeat;
  97.         }
  98.         if ((bh && bh->b_count != 1) || tmp != *ind) {
  99.             retry = 1;
  100.             brelse(bh);
  101.             continue;
  102.         }
  103.         *ind = 0;
  104.         ind_bh->b_dirt = 1;
  105.         brelse(bh);
  106.         minix_free_block(inode->i_sb,tmp);
  107.     }
  108.     ind = (unsigned short *) ind_bh->b_data;
  109.     for (i = 0; i < 512; i++)
  110.         if (*(ind++))
  111.             break;
  112.     if (i >= 512)
  113.         if (ind_bh->b_count != 1)
  114.             retry = 1;
  115.         else {
  116.             tmp = *p;
  117.             *p = 0;
  118.             minix_free_block(inode->i_sb,tmp);
  119.         }
  120.     brelse(ind_bh);
  121.     return retry;
  122. }
  123.         
  124. static int trunc_dindirect(struct inode * inode)
  125. {
  126.     int i, tmp;
  127.     struct buffer_head * dind_bh;
  128.     unsigned short * dind, * p;
  129.     int retry = 0;
  130. #define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
  131.  
  132.     p = 8 + inode->u.minix_i.i_data;
  133.     if (!(tmp = *p))
  134.         return 0;
  135.     dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
  136.     if (tmp != *p) {
  137.         brelse(dind_bh);
  138.         return 1;
  139.     }
  140.     if (!dind_bh) {
  141.         *p = 0;
  142.         return 0;
  143.     }
  144. repeat:
  145.     for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
  146.         if (i < 0)
  147.             i = 0;
  148.         if (i < DINDIRECT_BLOCK)
  149.             goto repeat;
  150.         dind = i+(unsigned short *) dind_bh->b_data;
  151.         retry |= trunc_indirect(inode,7+512+(i<<9),dind);
  152.         dind_bh->b_dirt = 1;
  153.     }
  154.     dind = (unsigned short *) dind_bh->b_data;
  155.     for (i = 0; i < 512; i++)
  156.         if (*(dind++))
  157.             break;
  158.     if (i >= 512)
  159.         if (dind_bh->b_count != 1)
  160.             retry = 1;
  161.         else {
  162.             tmp = *p;
  163.             *p = 0;
  164.             inode->i_dirt = 1;
  165.             minix_free_block(inode->i_sb,tmp);
  166.         }
  167.     brelse(dind_bh);
  168.     return retry;
  169. }
  170.         
  171. void minix_truncate(struct inode * inode)
  172. {
  173.     int retry;
  174.  
  175.     if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
  176.          S_ISLNK(inode->i_mode)))
  177.         return;
  178.     while (1) {
  179.         retry = trunc_direct(inode);
  180.         retry |= trunc_indirect(inode,7,inode->u.minix_i.i_data+7);
  181.         retry |= trunc_dindirect(inode);
  182.         if (!retry)
  183.             break;
  184.         current->counter = 0;
  185.         schedule();
  186.     }
  187.     inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  188.     inode->i_dirt = 1;
  189. }
  190.